<?php

declare (strict_types=1);

namespace app\common\service\user;

use app\common\exception\AdminException;
use app\common\repository\user\MechanismRepository;
use app\common\repository\user\UserRepository;
use app\common\service\BaseService;
use app\common\repository\user\UserInvestmentRepository;
use app\common\service\CodexPriceService;

class UserInvestmentService extends BaseService
{
    public function __construct(UserInvestmentRepository $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 获取列表
     *
     * @param $where
     * @return \think\model\Collection|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getList($where = []): \think\model\Collection|\think\Collection
    {
        return $this->repository->getByWhere($where, ['create_time' => 'desc']);
    }

    /**
     * 新增
     *
     * @param array $data
     * @return \think\Collection|\app\common\model\BaseModel|array
     * @throws \Exception
     */
    public function create(array $data): \think\Collection|\app\common\model\BaseModel|array
    {
        return $this->repository->save($data);
    }

    /**
     * 修改
     *
     * @param array $data
     * @param $where
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function update(array $data, $where): \app\common\model\BaseModel|bool|int
    {
        return $this->repository->update($data, $where);
    }

    /**
     * 获取详情
     *
     * @param $where
     * @return \app\common\model\BaseModel|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getInfo($where): ?\app\common\model\BaseModel
    {
        return $this->repository->getOne($where);
    }

    /**
     * 删除
     *
     * @param $where
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function delete($where): bool
    {
        return $this->repository->delete($where);
    }

    /**
     * 用户投资
     *
     * @param $user_id
     * @param $data
     * @return \app\common\model\BaseModel|array|\think\Collection|\think\model\contract\Modelable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function userInvestment($user_id, $data)
    {
        $userId = $user_id;
        $mechanismId = $data['mechanism_id'];
        $usdtAmount = $data['amount']; // 投资金额
        $txHash = trim($data['tx_hash']); // 交易哈希
        $time = time();

        // 验证金额是否为100的倍数
        if ($usdtAmount % 100 != 0) {
            throw new \Exception('投资金额必须是100的倍数');
        }

        // 可选：也可以验证最小金额
        if ($usdtAmount < 100) {
            throw new \Exception('投资金额不能小于100');
        }

        // 验证交易哈希格式
        if (empty($txHash) || !preg_match('/^0x[0-9a-fA-F]{64}$/', $txHash)) {
            throw new \Exception('交易哈希格式不正确');
        }

        $mechanismRep = app()->make(MechanismRepository::class);
        // 检查收益机制是否存在且开启
        $mechanismInfo = $mechanismRep->getOne([
            'status' => 1,
            'id' => $mechanismId,
        ]);
        if (!$mechanismInfo) {
            throw new AdminException('The profit mechanism does not exist or has been closed', 401);
        }

        return $this->transaction(function () use ($user_id, $mechanismId, $usdtAmount, $txHash, $time, $mechanismRep, $mechanismInfo, $userId) {
            // 投资USDT转换为codex资产
            $codePriceService = app()->make(CodexPriceService::class);
            $codexNewPrice = $codePriceService->getNewPrice();
            $codex_amount = $usdtAmount / $codexNewPrice;

            $userRep = app()->make(UserRepository::class);
            // 用户钱包地址
            $userAddress = $userRep->getValue('address', [
                'id' => $userId,
            ]);

            // 收益率
            $profitRatio = $mechanismInfo->profit_ratio;
            // 模式1-灵活:流动性挖矿 2-锁仓:内容收益预铸
            $mode = $mechanismInfo->mode;
            $expireTime = 0; // 锁仓到期时间

            if ($mode == 2) {
                $expireTime = time() + 365 * 86400;
            }

            return $this->repository->save([
                'address' => $userAddress,
                'user_id' => $userId,
                'mechanism_id' => $mechanismId,
                'usdt_amount' => $usdtAmount,
                'codex_amount' => $codex_amount,
                'mode' => $mode,
                'tx_hash' => $txHash,
                'invest_time' => $time,
                'status' => 1,
                'profit_ratio' => $profitRatio,
                'expire_time' => $expireTime,
            ]);
        });
    }

    /**
     * 赎回矿机
     *
     * @param $user_id
     * @param $data
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function redemption($user_id, $data): \app\common\model\BaseModel|bool|int
    {
        $id = $data['id'];
        $hash = $data['tx_hash'];
        $InvestmentInfo = $this->repository->getOne($id);
        $mechanismRep = app()->make(MechanismRepository::class);
        // 1. 检查收益机制是否存在且是灵活模式
        $mechanismInfo = $mechanismRep->getOne($InvestmentInfo->mechanism_id);
        if (!$mechanismInfo || $mechanismInfo->mode != 1) {
            throw new AdminException('Operation exception');
        }
        return $this->repository->update([
            'status' => 4,
            'close_tx_hash' => $hash,
            'close_time' => time(),
        ], ['id' => $id]);
    }

    /**
     * 获取参与记录
     *
     * @param $user_id
     * @param array $data
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     */
    public function getOrderList($user_id, array $data = []): array
    {
        [$page, $pageSize] = $this->getPaginationParams();
        $where['user_id'] = $user_id;
        if (!empty($data) && isset($data['status'])) {
            $where['status'] = $data['status'];
        }
        $data = $this->repository->paginate($where, ['create_time' => 'desc'], $page, $pageSize);
        $mechanismRep = app()->make(MechanismRepository::class);
        $mechanisms = $mechanismRep->getColumn('desc', [], 'id');
        foreach ($data['list'] as &$item) {
            $item['desc'] = $mechanisms[$item['mechanism_id']];
        }
        return $data;
    }


    /**
     * 调用区块链浏览器API验证交易
     *
     * @param $txHash
     * @param $toAddress
     * @param $expectedAmount
     * @return bool
     */
    public function verifyUsdtOnBsc($txHash, $toAddress, $expectedAmount): bool
    {
        $contractAddress = '0x55d398326f99059ff775485246999027b3197955'; // USDT-BEP20
        $apiKey = '6NBBQUXYQ4P97RHHRDNF6PHQB58XJXC8T9';

        $url = "https://api.bscscan.com/api" .
            "?module=account" .
            "&action=tokentx" .
            "&contractaddress=" . $contractAddress .
            "&address=" . $toAddress .
            "&apikey=" . $apiKey;

        $response = file_get_contents($url);
        if ($response === false) {
            return false;
        }

        $data = json_decode($response, true);

        if ($data['status'] != '1') {
            return false;
        }

        foreach ($data['result'] as $tx) {
            if ($tx['hash'] === $txHash && $tx['to'] === strtolower($toAddress)) {
                $amount = (float)$tx['value'] / pow(10, 18); // 转换为实际 USDT 数量
                return $amount >= $expectedAmount;
            }
        }

        return false; // 未找到该交易
    }
}